"""
@file: user_api.py
@author：wang
@time: 2022/2/23 0023 10:28
"""
import random
import uuid

from flask import Blueprint, jsonify, session
from flask_restful import Api, Resource, reqparse, inputs, fields, marshal
from werkzeug.security import generate_password_hash, check_password_hash

from apps.util import send_message, get_content
from exts import cache, db
from apps.models.user_models import User
rom tasks.sms import add

user_bp = Blueprint("user", __name__)

api = Api(user_bp)

# 输入：用于接受前端内容
sms_parser = reqparse.RequestParser()
sms_parser.add_argument("mobile", type=inputs.regex(r"^1[356789]\d{9}$"), help="手机号码格式错误", required=True,
                        location=["form", "args"])

"""
发送验证码
"""


class SendMessageApi(Resource):
    def post(self):
        res = add.delay(*(100, 200))
        print('*'*50)
        print(res)
        print('*' * 50)
        args = sms_parser.parse_args()
        mobile = args.get("mobile")
        ret, code = send_message(mobile)
        if ret is not None:
            if get_content(ret) == "000000":
                cache.set(mobile, code, timeout=1800)
                return jsonify(code=200, msg="短信发送成功")
            elif get_content(ret) == "160038":
                return jsonify(code=400, msg="短信验证码发送过频繁")
        else:
            return jsonify(code=400, msg="短信发送失败")


lr_parser = sms_parser.copy()
lr_parser.add_argument("code", type=inputs.regex(r"^\d{4}$"), help="必须输入四位验证码", required=True, location="form")

user_fields = {
    "id": fields.Integer,
    "username": fields.String()
}

"""
用户的登录和注册
"""


class LoginAndRegister(Resource):
    def post(self):
        args = lr_parser.parse_args()
        mobile = args.get("mobile")
        code = args.get("code")
        cache_code = cache.get(mobile)
        if code and int(code) == cache_code:
            # 数据库查找是否存在mobile
            user = User.query.filter(User.phone == mobile).first()
            # 判断列表中是否存在用户
            if not user:
                # 注册
                user = User()
                user.phone = mobile
                s = ""
                for i in range(13):
                    ran = random.randint(0, 9)
                    s + str(ran)
                user.username = "用户" + s
                db.session.add(user)
                db.session.commit()
            # 生成token值----存在于headers中Authorization
            token = str(uuid.uuid4()).replace("-", "") + str(random.randint(100, 999))
            print(token)
            # 存储登录的用户信息
            cache.set(token, mobile)
            return {"status": 200, "msg": "用户登录成功", "token": token}
        else:
            return {"errormsg": "验证码错误", "status": 400}


"""
忘记密码
"""


class ForgetPasswordApi(Resource):
    # 构建图片验证码
    def get(self):
        s = "AGDKSGUSAMEMGdisjfidslsipoieturqpo123t423dlfads"
        code = ""
        for i in range(4):
            code += random.choice(s)
        # 保存code
        session["code"] = code
        return {"code": code}


"""
忘记密码,生成图片验证码
"""

# 控制重置密码的输入部分
reset_parser = sms_parser.copy()
reset_parser.add_argument("imageCode", type=inputs.regex("^[a-z0-9A-Z]{4}$"), help="请输入正确格式的验证码")


class ResetPassword(Resource):
    def get(self):
        args = reset_parser.parse_args()
        mobile = args.get("mobile")
        imageCode = args.get("imageCode")  # 从ForgetPasswordApi请求中获取图行验证码
        code = session.get("code")
        if code and imageCode.lower() == code.lower():
            # 判断手机号码
            user = User.query.filter(User.phone == mobile).first()
            if user:
                # 发送手机验证码
                ret, code = send_message(mobile)
                if ret is not None:
                    if get_content(ret) == "000000":
                        cache.set(mobile, code, timeout=1800)
                        return jsonify(code=200, msg="短信发送成功")
                else:
                    return jsonify(code=400, msg="短信发送失败")
            else:
                return {"status": 400, "msg": "此用户请注册"}
        else:
            return {"status": 400, "msg": "验证码发送失败"}


"""
更新密码
客户端要传递的信息
"""
update_parser = lr_parser.copy()
update_parser.add_argument("code", type=inputs.regex(r"^\d{4}$"), help="必须输入4位验证码", location="form")
update_parser.add_argument("password", type=inputs.regex(r"^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$"),
                           help="必须包含大小写字母和数字的组合，不能使用特殊字符，长度在8-10之间", location="form")
update_parser.add_argument("repassword", type=inputs.regex(r"^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$"),
                           help="必须包含大小写字母和数字的组合，不能使用特殊字符，长度在8-10之间", location="form")


class UpdatePasswordApi(Resource):
    def post(self):
        args = update_parser.parse_args()
        code = args.get("code")  # 验证码
        mobile = args.get("mobile")  # 手机号
        cache_code = cache.get(mobile)  # 在redis中提取验证码
        # 判断验证码是否输入正确
        if cache_code and cache_code == int(code):
            user = User.query.filter(User.phone == mobile).first()
            password = args.get("password")
            repassword = args.get("repassword")
            # 判断密码是否一致
            if password == repassword:
                user.password = generate_password_hash(password)
                db.session.commit()
                return {"status": 200, "msg": "设置成功"}
            else:
                return {"status": 400, "msg": "两次密码不一致"}
        else:
            return {"status": 400, "msg": "验证码输入有误"}


"""
密码登录
"""
# 设置前端传递过来的数据
password_login_resource = sms_parser.copy()
password_login_resource.add_argument("password", type=str, help="必须输入密码", location="form", required=True)


class PasswordLoginApi(Resource):
    def post(self):
        args = password_login_resource.parse_args()
        mobile = args.get("mobile")
        password = args.get("password")
        user = User.query.filter(User.phone == mobile).first()
        if user:
            # 验证密码是否一致
            if check_password_hash(user.password, password):
                # 说明用户登录成功
                cache.set(mobile + "_", 1)
                return {"status": 200, "msg": "用户登录成功"}
        else:
            return {"status": 400, "msg": "账户名或密码错误"}


"""
将密码更新、密码登录整合为一个API
"""


class UserApi(Resource):
    def post(self):
        """
       密码登录
       """
        args = password_login_resource.parse_args()
        mobile = args.get("mobile")
        password = args.get("password")
        user = User.query.filter(User.phone == mobile).first()
        if user:
            # 验证密码是否一致
            if check_password_hash(user.password, password):
                # 说明用户登录成功
                token = str(uuid.uuid4()).replace("-", "") + str(random.randint(100, 999))
                print(token)
                # 存储登录的用户信息
                cache.set(token, mobile)
                return {"status": 200, "msg": "用户登录成功", "token": token}
        else:
            return {"status": 400, "msg": "账户名或密码错误"}

    def put(self):
        """
        更新密码
        客户端要传递的信息
        :return:
        """
        args = password_login_resource.parse_args()
        code = args.get("code")  # 验证码
        mobile = args.get("mobile")  # 手机号
        cache_code = cache.get(mobile)  # 在redis中提取验证码
        # 判断验证码是否输入正确
        if cache_code and cache_code == int(code):
            user = User.query.filter(User.phone == mobile).first()
            password = args.get("password")
            repassword = args.get("repassword")
            # 判断密码是否一致
            if password == repassword:
                user.password = generate_password_hash(password)
                db.session.commit()
                return {"status": 200, "msg": "设置成功"}
            else:
                return {"status": 400, "msg": "两次密码不一致"}
        else:
            return {"status": 400, "msg": "验证码输入有误"}

    def delete(self):
        """
        用户退出
        :return:
        """
        args = password_login_resource.parse_args()
        mobile = args.get("mobile")
        cache.delete(mobile)
        cache.delete(mobile + "_")
        return {"status": 200, "msg": "用户退出成功"}


api.add_resource(SendMessageApi, "/sms")
api.add_resource(LoginAndRegister, "/code_login")
api.add_resource(ForgetPasswordApi, "/forget")
api.add_resource(ResetPassword, "/reset")
# api.add_resource(UpdatePasswordApi, "/update")
# api.add_resource(PasswordLoginApi, "/password_login")
api.add_resource(UserApi, "/user")
